# ============================================================
# * Copyright © hk. 2022-2025. All rights reserved.
# * File name: CMakeLists.txt
# * Author   : 苏木
# * Date     : 2025-05-22
# * Version  : 
# * Description: cmake version 3.16.3
# ============================================================
## https://cmake.com.cn/cmake/help/latest/guide/tutorial/index.html
## https://cmake.org/cmake/help/latest/

# 指定 CMake 的最低版本要求
# --------------------------------------------------
cmake_minimum_required(VERSION 3.10)


# 设置项目名称和使用的编程语言
# --------------------------------------------------
project(SPROJECT C)
set(app_target "app_demo.out")

# 启用/禁用在生成期间输出编译命令。会生成compile_commands.json文件,包含编译命令，可以被clangd使用实现跳转和补全
# --------------------------------------------------
# 注意,这个选项放在PROJECT之前的话可能导致第一次构建不生效
# SET(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "Enable compile commands export" FORCE) # 强制设置变量并更新缓存
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)


# 设置C编译器
# --------------------------------------------------
# set(CMAKE_C_COMPILER "/home/sumu/2software/gcc-arm-linux-gnueabihf-8.3.0/bin/arm-linux-gnueabihf-gcc")
set(CMAKE_C_COMPILER "gcc")
message(STATUS "[USER:TOP]CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}") # c编译器，一般默认是gcc


# 设置C编译选项,要放在 add_executable 之前
# --------------------------------------------------
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
add_compile_options(-g -Wall) # 不会去修改 CMAKE_C_FLAGS，一般还是建议用这个


# 指定可执行程序和源文件
# --------------------------------------------------
include_directories(func_version)           # 添加头文件目录
add_subdirectory(func_version)              # 添加子目录（会自动执行子目录的CMakeLists.txt）

set(src_list main.c)                        # 设置main函数源文件
add_executable(${app_target} ${src_list})
target_link_libraries(${app_target} func_version_shared) # 链接动态库（不自动包含头文件路径）


# 获取目标的属性,要先指定目标才能获取
# --------------------------------------------------
get_target_property(app_compile_options app_demo.out COMPILE_OPTIONS) # 获取编译选项属性
message(STATUS "[USER:TOP]Target Compile Options: ${app_compile_options}")
message(STATUS "[USER:TOP]CMAKE_C_FLAGS         : ${CMAKE_C_FLAGS}")      # c编译选项


# 说明
# --------------------------------------------------
# shared lib name: libfunc_version_shared.so 
# path           : build/func_version/libfunc_version_shared.so
# executable path: build/app_demo.out

# 1.查看 build/func_version/libfunc_version_shared.so 是否为动态库
# 
# sumu@sumu-virtual-machine:$ file build/func_version/libfunc_version_shared.so
# 输出如下：
# 	build/func_version/libfunc_version_shared.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), 
# 	dynamically linked, BuildID[sha1]=a2a75dcd6a6703345a2a61ee7fcc311fbc1e67cd, with debug_info, not stripped

# 2.为什么编译完成后，可以直接执行 ./build/app_demo.out？
# CMake 的 RPATH 机制，RPATH是一个嵌入在可执行文件中的动态库搜索路径，运行时优先从这些路径查找动态库，在cmake 3.9之后的版本中，使用了新策略，是叫RUNPATH。
# 当使用 target_link_libraries() 链接动态库时，CMake 会自动将动态库的输出路径写入可执行文件的 RPATH，这使得运行时能直接找到同构建目录下的动态库
# 
# sumu@sumu-virtual-machine:$ readelf -d build/app_demo.out | grep -E 'RPATH|RUNPATH|NEEDED'
# 输出如下：
#  0x0000000000000001 (NEEDED)             共享库：[libfunc_version_shared.so]
#  0x0000000000000001 (NEEDED)             共享库：[libc.so.6]
#  0x000000000000001d (RUNPATH)            Library runpath: [/home/sumu/.../build/func_version]
# RPATH与RUNPATH：在 Linux 系统中，RPATH 和 RUNPATH 是动态链接器 (ld.so) 用来查找共享库的两种机制。它们的核心区别在于 搜索顺序 和 兼容性，
# 而生成 RUNPATH 而非 RPATH 通常与 链接器选项 和 构建工具（如 CMake）的配置 相关。
# 
